<template>
  <div id="threeId" ref="elementRef" class="panel"></div>
</template>

<script setup>
import * as THREE from 'three'
import {Vector2,Raycaster} from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js'
import { Lut, ColorMapKeywords } from 'three/examples/jsm/math/Lut.js';
import vertexShader from "./shader/vt-w.glsl";
import fragmentShader from "./shader/gm.glsl";
import { ref, onMounted, onBeforeUnmount } from 'vue'

let width, height, scene, camera, renderer, controls
let model, dirLight, plane
let animations, gui
let meshObj = {}
// let mixer = new THREE.AnimationMixer(model)
let clock = new THREE.Clock()
const elementRef = ref(null)
// 进行 raycasting（光线投射）。光线投射用于进行鼠标拾取（在三维空间中计算出鼠标点击了什么物体）
const rayCaster = new Raycaster()
// 获取鼠标坐标 处理点击某个模型的事件
const mouse = new Vector2()

onMounted(() => {
  const element = elementRef.value
  width = element.offsetWidth
  height = element.offsetHeight
  initScene()
  initModel()
  initShadow()
  render()
  document.addEventListener('click',clickEvent, false )
})

function initScene() {
  // 初始化场景: 创建场景，相机，物体，渲染器
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x888888)
  camera = new THREE.PerspectiveCamera(60, width / height, 1, 10000)
  camera.position.set(0, 0, 0)
  scene.add(camera)

  //三维坐标
  const axesHelper = new THREE.AxesHelper(40)
  scene.add(axesHelper)
  axesHelper.setColors(0xff0000,0x00ff00,0x0000ff);

  renderer = new THREE.WebGLRenderer({
    antialias: true, // 开启抗锯齿
    alpha: true
  })
  renderer.setClearColor(0x000000,0); //0是完全透明，1是不透明
  renderer.setSize(width, height)
  elementRef.value.appendChild(renderer.domElement)
  controls = new OrbitControls(camera, renderer.domElement)
// 使动画循环使用时阻尼或自转 意思是否有惯性
  controls.enableDamping = true;

  controls.dampingFactor = 0.05;

  controls.screenSpacePanning = false;

  controls.minDistance = 10;
  controls.maxDistance = 2000;

  // controls.maxPolarAngle = Math.PI / 2;

  // 光
  const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444)
  scene.add(hemiLight)
  dirLight = new THREE.DirectionalLight(0xffffff)
  dirLight.position.set(-5, 2, 0)
  scene.add(dirLight)
}
function setOtherOpacity(obj) {
  const loop = (children) => {
    children.forEach((item) => {
      if (item.isMesh && item.name !== '11111' && item.name !== '22222') {
        item.material.transparent = true
        item.material.opacity = 0.5
      }
      if (item.isMesh && (item.name === '11111' || item.name == '22222')) {
        meshObj[item.uuid] = item
        item.castShadow = true
      }
      loop(item.children || [])
    })
  }
  loop(obj.children)
}
function initModel() {
  // const planeGeometry = new THREE.PlaneGeometry(10, 10)
  // const planeMaterial = new THREE.MeshPhongMaterial({
  //   color: new THREE.Color('#c0c0c0'),
  //   side: THREE.DoubleSide,
  // })
  // plane = new THREE.Mesh(planeGeometry, planeMaterial)
  // // plane.rotateX(Math.PI / 2)
  // scene.add(plane)
  const loader = new GLTFLoader()
  loader.load('./full.glb', (glb) => {
    model = glb.scene
    animations = glb.animations
    // model.rotateX(Math.PI)
    model.scale.set(1,1,1);
    model.traverse((item) => {
      // setOtherOpacity(item)
      if (item.isMesh) {
        // item.material.color.set('#0674f5');

        // meshObj[item.uuid] = item
        // item.castShadow = true
      }
    })
    scene.add(model)
  })
}
function initShadow() {
  // plane.receiveShadow = true
  dirLight.castShadow = true
  renderer.shadowMap.enabled = true
}
function render() {
  requestAnimationFrame(render)
  const delta = clock.getDelta()
  controls.update()
  renderer.render(scene, camera)
  // mixer.update(delta)
}
const calMeshSize = (mesh) => {
  const pos = mesh.geometry.attributes.position;
  const count = pos.count;

  // 1. 计算模型y坐标高度差
  const yArr = [];//顶点所有y坐标，也就是地形高度
  const xArr = [];//顶点所有y坐标，也就是地形高度
  for (let i = 0; i < count; i++) {
    yArr.push(pos.getY(i));//获取顶点y坐标，也就是地形高度
    xArr.push(pos.getX(i));//获取顶点y坐标，也就是地形高度
  }
  yArr.sort();//数组元素排序，从小到大
  const miny = yArr[0];//y最小值
  const maxy = yArr[yArr.length - 1];//y最大值
  const height = maxy - miny; //山脉整体高度

  xArr.sort();//数组元素排序，从小到大
  const minx = xArr[0];//y最小值
  const maxx = xArr[xArr.length - 1];//y最大值
  const width = maxx - minx; //山脉整体高度
  return {
    width: Math.abs(width),
    height: Math.abs(height),
  }
}
const setMeshColor = (mesh) => {
  mesh.material.vertexColors = true
  const colors = [];
  const geometry = mesh.geometry
  const position = geometry.attributes.position
  for(let i=0; i<position.count; i++){
    // const p = new THREE.Vector3(position.array[i*3],position.array[i*3+1],position.array[i*3+2]);
    const color = new THREE.Color();
    colors.push(1, 0, 0);
    colors.push(0, 1, 0);
    // colors.push(0, 0, 1, 1);
  }

  geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
}
const getTextTure = () => {
  // let lut = new Lut();
  // let params = {
  //   colorMap: 'rainbow',
  // };
  // ColorMapKeywords.diy =  [
  //   [ 0.0, 0xFF0000 ], [ 0.1, 0xFF0000 ], [ 0.2, 0xFF0000 ]
  // ]
  // lut.setColorMap('diy');
  //
  // const texture = new THREE.CanvasTexture(lut.createCanvas());
  // return texture


  const canvas = document.createElement("canvas");
  const width = 30
  const height = 260
  canvas.width = width;
  canvas.height = height;
  let c = canvas.getContext('2d');
  const grd = c.createLinearGradient(0,0,width, height)
  grd.addColorStop(0, 'rgba(255,0,0,1)')
  grd.addColorStop(1, 'rgba(0,0,0,0.3)')
  c.fillStyle = grd
  c.fillRect(0,0,width,height)

// 创建CanvasTexture
  var texture = new THREE.CanvasTexture(canvas);
  return texture

}
const updateColors_shader = (mesh) => {
  let updatecolor_shaderMaterial = new THREE.ShaderMaterial({
    transparent: true,
    vertexShader,
    fragmentShader,
    uniforms: {
      colorA: { value: new THREE.Color(0xff0000) }, // 红色,
      colorB: { value: new THREE.Color(0x00ff00) } // 绿色
    }
  });
  const size = calMeshSize(mesh)
  console.log("!!!!!!!!!:",mesh,size);
  if(mesh.material instanceof Array){
    mesh.material.push(updatecolor_shaderMaterial);
  }else{
    mesh.material= updatecolor_shaderMaterial;
  }
}
const clickEvent = (event) => {
  // 得到鼠标相对于容器的坐标, 如果是div容器，需要改成div的宽高以及用event.layerX layerY
  // mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
  // mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
  mouse.x = ( event.layerX / elementRef.value.offsetWidth ) * 2 - 1;
  mouse.y = - ( event.layerY / elementRef.value.offsetHeight ) * 2 + 1;

  // 执行射线检测
  rayCaster.setFromCamera(mouse, camera);
  // 射线涉及到的物体集合
  const intersects = rayCaster.intersectObjects(scene.children, true)
  intersects.forEach((item) => {
    const mesh = item.object
    if (meshObj[mesh.uuid]) {
      const size = calMeshSize(mesh)
      console.log(mesh, size)
      // mesh.material.color.set('#ff0000');
      // setMeshColor(mesh)
      mesh.material = new THREE.ShaderMaterial({
        transparent: true,
        vertexShader,
        fragmentShader,
        uniforms: {
          color1: { value: new THREE.Color(0xff0000) },
          color2: { value: new THREE.Color(0x00ff00) },
          width: {value: size.width },
        },
      });
      updateColors_shader(mesh)
    }

  })
}

onBeforeUnmount(() => {
  if (gui) {
    // 销毁操作-清空场景、从DOM上删除渲染器等
    scene.remove(camera)
    // 停止渲染循环
    cancelAnimationFrame(render)
    // 释放渲染器的内存
    renderer.forceContextLoss() // 强制上下文丢失
    // 释放所有相关内容
    renderer.dispose()
    gui.destroy()
    gui = null
  }
})
</script>
<style lang="scss" scoped>
.panel{
  position: relative;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
</style>
